// ... existing code ...
/**
 * @file widget.cpp
 * @brief 网络调试助手服务端主窗口实现文件
 * @details 包含Widget类的所有成员函数实现，处理TCP服务器创建、客户端连接、数据收发等核心功能
 */
#include "widget.h"
#include "ui_widget.h"

#include <QMessageBox>
#include <QNetworkInterface>
#include <QTcpSocket>
#include <QTextCodec>

/**
 * @brief Widget类构造函数
 * @details 初始化UI组件，创建TCP服务器实例，建立信号槽连接，设置初始UI状态，并加载本地IP地址到下拉框
 * @param parent 父窗口指针
 */
Widget::Widget(QWidget *parent)
    : QWidget(parent)  // 初始化父类QWidget
    , ui(new Ui::Widget)  // 创建UI对象
{
    ui->setupUi(this);  // 设置UI

    server = new QTcpServer(this);  // 创建TCP服务器实例

    // 连接自定义组合框点击信号与刷新槽函数
    connect(ui->comboBoxChildren,&MyComboBox::on_ComboBox_clicked,this,&Widget::mComboBox_refresh);
    // 连接服务器新连接信号与处理槽函数
    connect(server,SIGNAL(newConnection()),this,SLOT(on_newClient_connect()));
    // 初始禁用断开按钮和停止监听按钮
    ui->btnLineout->setEnabled(false);
    ui->btnStopListen->setEnabled(false);

    // 获取本地所有IPv4地址并添加到地址选择下拉框
    QList<QHostAddress> addresss = QNetworkInterface::allAddresses();
    for(QHostAddress tmp : addresss){
        if(tmp.protocol() == QAbstractSocket::IPv4Protocol){
            ui->comboBoxAddr->addItem(tmp.toString());
        }
    }
}

/**
 * @brief Widget类析构函数
 * @details 释放UI资源
 */
Widget::~Widget()
{
    delete ui;  // 释放UI对象内存
}

/**
 * @brief 处理新客户端连接请求
 * @details 检查是否有挂起的连接，接受客户端连接，记录客户端地址和端口信息，并在UI中显示
 *          同时建立客户端数据接收和状态变化的信号槽连接
 */
void Widget::on_newClient_connect()
{

    // 检查是否有挂起的连接
    if(server->hasPendingConnections()){
        // 获取下一个挂起的连接
        QTcpSocket *connction = server->nextPendingConnection();
        qDebug() << "client Addr: " << connction->peerAddress().toString() << "port:" << connction->peerPort();
        // 在接收文本框中显示客户端连接信息
        ui->textEditRev->insertPlainText("客户端地址:"+connction->peerAddress().toString()+
                                         "客户端端口号："+QString::number(connction->peerPort()) +"\n");

        // 连接客户端数据接收信号与处理槽函数
        connect(connction,SIGNAL(readyRead()),this,SLOT(on_readyRead_handler()));
        // 连接客户端状态变化信号与处理槽函数
        connect(connction,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
                this,SLOT(mstateChanged(QAbstractSocket::SocketState)));
    }
}

/**
 * @brief 处理客户端数据接收
 * @details 从发送信号的客户端套接字中读取所有可用数据，并在接收文本框中显示
 */
void Widget::on_readyRead_handler()
{
    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());  // 获取发送信号的套接字对象

    QByteArray revData = tmpSock->readAll();  // 读取所有可用数据
    ui->textEditRev->insertPlainText("客户端: " + revData);  // 在文本框中显示接收到的数据
}

/**
 * @brief 处理客户端断开连接
 * @details 记录客户端断开信息，在接收文本框中显示，并安排套接字对象的延迟删除
 */
void Widget::mdisconnected()
{
    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());  // 获取发送信号的套接字对象
    qDebug() << "client out!";  // 输出调试信息
    ui->textEditRev->insertPlainText("客户端断开！");  // 在文本框中显示断开信息
    tmpSock->deleteLater();  // 延迟删除套接字对象
}

/**
 * @brief 处理客户端连接状态变化
 * @details 根据客户端套接字状态变化更新UI显示，处理连接和断开事件
 * @param socketState 新的套接字状态
 */
void Widget::mstateChanged(QAbstractSocket::SocketState socketState)
{
    QTcpSocket *tmpSock = qobject_cast<QTcpSocket *>(sender());  // 获取发送信号的套接字对象
    qDebug() << "client out In state:" << socketState;  // 输出调试信息
    switch(socketState){
    case QAbstractSocket::UnconnectedState:
        // 客户端断开连接时更新UI并清理资源
        ui->textEditRev->insertPlainText("客户端断开！");
        tmpSock->deleteLater();
        break;
    case QAbstractSocket::ConnectedState:
    case QAbstractSocket::ConnectingState:
        // 客户端连接或正在连接时更新UI
        ui->textEditRev->insertPlainText("客户端接入！");
        break;
    }
}

/**
 * @brief 刷新客户端列表下拉框
 * @details 清除现有列表项，获取所有当前连接的客户端套接字，将客户端端口号添加到下拉框，并添加"all"选项用于群发
 */
void Widget::mComboBox_refresh()
{
    ui->comboBoxChildren->clear();  // 清除下拉框现有项
    QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();  // 获取所有客户端套接字

    for(QTcpSocket* tmp:tcpSocketClients){
        if(tmp!=nullptr)
            ui->comboBoxChildren->addItem(QString::number(tmp->peerPort()));  // 添加客户端端口号到下拉框
    }
    ui->comboBoxChildren->addItem("all");  // 添加"all"选项用于群发
}


/**
 * @brief 处理监听按钮点击事件
 * @details 从UI获取端口号，尝试启动TCP服务器监听，成功则更新按钮状态，失败则显示错误消息
 */
void Widget::on_btnListen_clicked()
{
    // 从UI获取端口号
    int port = ui->lineEditPort->text().toInt();
    // 尝试在指定地址和端口上启动监听
    if(!server->listen(QHostAddress(ui->comboBoxAddr->currentText()),port)){
        qDebug() << "listenError";  // 输出调试信息
        QMessageBox msgBox;  // 创建消息框
        msgBox.setWindowTitle("监听失败");  // 设置消息框标题
        msgBox.setText("端口号被占用");  // 设置消息框内容
        msgBox.exec();  // 显示消息框
        return;
    }
    // 监听成功，更新按钮状态
    ui->btnListen->setEnabled(false);
    ui->btnLineout->setEnabled(true);
    ui->btnStopListen->setEnabled(true);
}

/**
 * @brief 处理发送按钮点击事件
 * @details 根据下拉框选择，向指定客户端或所有客户端发送文本框中的数据
 */
void Widget::on_btnSend_clicked()
{
    QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();  // 获取所有客户端套接字
    // 判断是否向所有客户端发送
    if(ui->comboBoxChildren->currentText() != "all"){
        // 向选中的单个客户端发送数据
        tcpSocketClients[childIndex]->write(ui->textEditSend->toPlainText().toStdString().c_str());
    }else{
        // 向所有客户端广播数据
        for(QTcpSocket* tmp:tcpSocketClients){
           QByteArray sendData = ui->textEditSend->toPlainText().toLocal8Bit();
            tmp->write(sendData);
        }
    }
}

/**
 * @brief 处理客户端选择下拉框变化事件
 * @details 记录用户选择的客户端索引，用于后续数据发送
 * @param index 选中项的索引
 */
void Widget::on_comboBoxChildren_activated(int index)
{
    childIndex = index;  // 记录选中的客户端索引
}

/**
 * @brief 处理停止监听按钮点击事件
 * @details 关闭所有客户端连接，停止服务器监听，并重置按钮状态
 */
void Widget::on_btnStopListen_clicked()
{
    QList<QTcpSocket*> tcpSocketClients =  server->findChildren<QTcpSocket*>();  // 获取所有客户端套接字
    // 关闭所有客户端连接
    for(QTcpSocket* tmp:tcpSocketClients){
        tmp->close();
    }

    // 停止服务器监听
    server->close();
    // 重置按钮状态
    ui->btnListen->setEnabled(true);
    ui->btnLineout->setEnabled(false);
    ui->btnStopListen->setEnabled(false);

}

/**
 * @brief 处理断开按钮点击事件
 * @details 停止服务器并关闭窗口
 */
void Widget::on_btnLineout_clicked()
{
    server->close();  // 停止服务器
    close();  // 关闭窗口
}
